package net.esj.basic.utils.view;

import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

import net.esj.basic.annotation.IgnorePrint;
import net.esj.basic.pojo.Updater;
import net.esj.basic.utils.DateFormat;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONString;

public class JSONUtil {
	
		private static JSONUtil instance = null;
	   
	   public JSONUtil(){}
	  
	  
	    protected Object proxyCheck(Object bean){
	    	if(bean instanceof Updater){
	    		return null;
	    	}
	        return bean;
	    }

	    static public String toJSONString(Object obj) throws JSONException{
	        return toJSONString(obj,null, false);
	    }
	   
	    static public String toJSONString(Object obj,Class structClass, boolean useClassConvert) throws JSONException{
	        if(instance == null)
	            instance = new JSONUtil();
	        return instance.getJSONObject(obj,structClass, useClassConvert).toString();
	    }

	    private String getJSONArray(Object arrayObj, boolean useClassConvert) throws JSONException{
	       
	        if(arrayObj == null)
	            return "null";
	       
	        arrayObj = proxyCheck(arrayObj);
	       
	        JSONArray jSONArray = new JSONArray();
	        if(arrayObj instanceof Collection){
	            Iterator iterator = ((Collection)arrayObj).iterator();
	            while(iterator.hasNext()){
	                Object rowObj = iterator.next();
	                if(rowObj == null)
//	                    jSONArray.put(new JSONStringObject(null));
	                	jSONArray.put(new JSONStringObject("null"));
	                else if(rowObj.getClass().isArray() || rowObj instanceof Collection)
	                    jSONArray.put(getJSONArray(rowObj, useClassConvert));
	                else
	                    jSONArray.put(getJSONObject(rowObj,null, useClassConvert));
	            }
	        }
	        if(arrayObj.getClass().isArray()){
	            int arrayLength = Array.getLength(arrayObj);
	            for(int i = 0; i < arrayLength; i ++){
	                Object rowObj = Array.get(arrayObj, i);
	                if(rowObj == null)
	                    //jSONArray.put(new JSONStringObject(null));
	                	jSONArray.put(new JSONStringObject("null"));
	                else if(rowObj.getClass().isArray() || rowObj instanceof Collection)
	                    jSONArray.put(getJSONArray(rowObj, useClassConvert));
	                else
	                    jSONArray.put(getJSONObject(rowObj,null, useClassConvert));
	            }
	        }
	        return jSONArray.toString();
	    }

	    public JSONStringObject getJSONObject(Object value, Class structClass, boolean useClassConvert) throws JSONException{

	        //处理原始类型
	        if (value == null) {
	            return new JSONStringObject("null");
	        }
	        
	        value = proxyCheck(value);
	        if (value == null) {
	            return new JSONStringObject("null");
	        }
	        if (value instanceof JSONString) {
	            Object o;
	            try {
	                o = ((JSONString)value).toJSONString();
	            } catch (Exception e) {
	                throw new JSONException(e);
	            }
	            throw new JSONException("Bad value from toJSONString: " + o);
	        }
	        if (value instanceof Number){
	            return new JSONStringObject(JSONObject.numberToString((Number) value));
	        }
	        if ( value instanceof JSONObject ||
	                value instanceof JSONArray) {
	            return new JSONStringObject(value.toString());
	        }
	        if (value instanceof String)
	            return new JSONStringObject(JSONObject.quote(value.toString()));
	        if (value instanceof Map) {
	           
	            JSONObject jSONObject = new JSONObject();

	            Iterator iterator = ((Map)value).keySet().iterator();
	            while(iterator.hasNext()){
	                String key = iterator.next().toString();
	                Object valueObj = ((Map)value).get(key);
	                jSONObject.put(key, getJSONObject(valueObj,structClass, useClassConvert));
	            }
	            return new JSONStringObject(jSONObject.toString());
	        }

	        //class
	        if(value instanceof Class)
	            return new JSONStringObject(JSONObject.quote(((Class)value).getSimpleName()));
	       
	        //数组
	        if (value instanceof Collection || value.getClass().isArray()) {
	            return new JSONStringObject(getJSONArray(proxyCheck(value), useClassConvert));
	        }

	        if(value instanceof Date){
	        	  return new JSONStringObject("\""+DateFormat.formateDateTime((Date)value, DateFormat.DEFAULT_DATETIME_FORMAT_SEC)+"\"");
	        }
	        
	        if(value instanceof Boolean){
	        	if(!(Boolean)value){
	        		return new JSONStringObject("false");
//	        		return new JSONStringObject("\"<font color='red'>否</font>\"");
	        	}else{
	        		return new JSONStringObject("true");
//	        		return new JSONStringObject("\"<font color='red'>是</font>\"");
	        	}
	        }
	        
	        return reflectObject(value,structClass, useClassConvert);
	    }//value.equals(null)

	    protected JSONStringObject reflectObject(Object bean,Class structClass, boolean useClassConvert) {
	        JSONObject jSONObject = new JSONObject();

	        Class klass = bean.getClass();
	        if(structClass!=null){
	        	klass = structClass;
	        }
	        Method[] methods = klass.getMethods();
	        for (int i = 0; i < methods.length; i += 1) {
	            try {
	                Method method = methods[i];
	                method.setAccessible(true);
	                String name = method.getName();
	                String key = "";
	                if(method.isAnnotationPresent(IgnorePrint.class)){
	                	continue;
	                }
	                if (name.startsWith("get")) {
	                    key = name.substring(3);
	                } else if (name.startsWith("is")) {
	                    key = name.substring(2);
	                }
	                if (key.length() > 0 &&
	                        Character.isUpperCase(key.charAt(0)) &&
	                        method.getParameterTypes().length == 0) {
	                    if (key.length() == 1) {
	                        key = key.toLowerCase();
	                    } else if (!Character.isUpperCase(key.charAt(1))) {
	                        key = key.substring(0, 1).toLowerCase() +
	                            key.substring(1);
	                    }
	                    Object elementObj = method.invoke(bean, null);
	                    if(!useClassConvert && elementObj instanceof Class)
	                        continue;

	                    jSONObject.put(key, getJSONObject(elementObj,structClass, useClassConvert));
	                }
	            } catch (Exception e) {
	                e.printStackTrace();
	            }
	        }
	        return new JSONStringObject(jSONObject.toString());
	    }
	}

//	输出：
//	var jsonStr = "{"AList":["hello",false,{"innerhm":{"gigi":"高兴","sina":7.4353999999999995651478457148186862468719482421875}},{}],"ii":7,"oarray":[352,false,"kick"],"ss":"你好","bb":true}";
//
//	如果需要支持Hibernate，那么必须弄清其机制。Hibernate采用CGLIB对VO对象进行字节码增加，实际机制就是使用一个原类型的proxy子类，其子类实现了HibernateProxy接口。其接口有一个isUninitialized的判断方法，用来判断该代理类是否已经初始化（还记得在事务外使用延迟加载的对象会抛no Session的错误吗，正是由于实际使用的对象已经变成原来类的子类proxy了）。而对于one-to-many映射时，很难判断对象只加载一次，因此为了避免递归调用死循环，忽略了Hibernate的one-to-many集合的递归反射。其原理和many-to-one一样，也是一个子类化的proxy，具有PersistentSet的接口。
//
//	因此，支持Hibernate的JSONUtil如下：
